package cn.micai.base.concurrent;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 描述：使用原子量的特性实现取款操作的原子性
 * <p>
 *
 * @author: 赵新国
 * @date: 2018/5/14 11:18
 */
public class AtomicAccout {

    AtomicLong balance;

    public AtomicAccout(AtomicLong money) {
        this.balance = money;
        System.out.println("Totle Money: " + balance);
    }

    /**
     * 存款
     * @param money
     */
    public void deposit(long money) {
        balance.addAndGet(money);
    }

    /**
     * 取款
     * @param money
     * @param delay
     */
    public void withdraw(long money, int delay) {
        long oldValue = balance.get();
        if (oldValue >= money) {
            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**
             * 这个方法在执行的时候是原子化的，首先比较所读取的值是否和被修改的值一致，如果一致则执行原子化修
             * 改，否则失败。如果帐余额在读取之后，被修改了，则 compareAndSet 会返回 FALSE，则余额修改失败，不能完成取款操作
             */
            if (balance.compareAndSet(oldValue, oldValue - money)) {
                System.out.println(Thread.currentThread().getName() + " withdraw " + money + " successful! " + balance);
            } else {
                System.out.println(Thread.currentThread().getName() + " thread concurrent, withdraw failed! " + balance);
            }
        } else {
            System.out.println(Thread.currentThread().getName()+" balance is not enough, withdraw failed! " + balance);
        }
    }

    public long get() {
        return balance.get();
    }

    private static class AtomicAccountThread extends Thread {

        AtomicAccout accout;
        int delay;
        public AtomicAccountThread(AtomicAccout accout, int delay) {
            this.accout = accout;
            this.delay = delay;
        }

        @Override
        public void run() {
            accout.withdraw(100, delay);
        }
    }

    public static void main(String [] args) {
        AtomicAccout accout = new AtomicAccout(new AtomicLong(100));
        AtomicAccountThread aat1 = new AtomicAccountThread(accout, 1000);
        AtomicAccountThread aat2 = new AtomicAccountThread(accout, 0);
        aat1.start();
        aat2.start();

        Map<String, Object> map = new HashMap<String, Object>(2);

        // 只有当没有找到匹配key的值时，才写入值
        map.putIfAbsent("1", "您好，检查并写入");
        System.out.println(map.get("1"));

        // 只有当key与oldValue匹配时才取代
        map.replace("1", "您好，检查并写入", "您好，赵新国");
        System.out.println(map);

        //
        map.replace("1", "您好，李思慧");
        System.out.println(map);

        // 只有当key与value匹配时才移除
        map.remove("1", "您好，赵新国");
        System.out.println(map.get("1"));


    }

}
